/**
 * @file system_data.h
 * @brief 系统数据模块 - 处理系统命令相关的所有数据类型
 * @details 本头文件定义了104协议中系统数据类型的结构体和操作函数，
 *          包括总召唤命令、时钟同步命令、复位进程命令等。
 *          支持完整的数据创建、转换和验证功能。
 * 
 * @author zyb
 * @date 2025-10-13
 * @version 1.0
 * 
 * @note 所有数据类型都遵循IEC 60870-5-104协议规范
 * @warning 系统命令涉及设备控制，需要严格验证
 * 
 * @see protocol_types.h
 * @see error_codes.h
 * @see validation_utils.h
 */

#ifndef SYSTEM_DATA_H
#define SYSTEM_DATA_H

#include "../../common/types/include/protocol_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/* ==================== 系统命令数据类型定义 ==================== */

/**
 * @brief 召唤限定词 (Qualifier of Interrogation)
 */
typedef struct {
    uint8_t qoi : 7;    /* 召唤限定词 */
    uint8_t res : 1;    /* 预留 */
} qoi_interrogation_t;

/**
 * @brief 初始化原因 (Cause of Initialization)
 */
typedef struct {
    uint8_t coi : 7;    /* 初始化原因 */
    uint8_t res : 1;    /* 预留 */
} coi_t;

/**
 * @brief 复位进程命令限定词 (Reset Process Command Qualifier)
 */
typedef struct {
    uint8_t qrp : 7;    /* 复位进程命令限定词 */
    uint8_t res : 1;    /* 预留 */
} qrp_t;

/**
 * @brief 总召唤命令结构 (C_IC_NA_1)
 */
typedef struct {
    info_addr_t info_address;   /* 信息对象地址 (=0) */
    qoi_interrogation_t qualifier;           /* 召唤限定词 */
} C_IC_NA_1_t;

/**
 * @brief 时钟同步命令结构 (C_CS_NA_1)
 */
typedef struct {
    info_addr_t info_address;   /* 信息对象地址 (=0) */
    cp56time2a_t timestamp;     /* CP56Time2a时间戳 */
} C_CS_NA_1_t;

/**
 * @brief 初始化命令结构 (C_CI_NA_1)
 */
typedef struct {
    info_addr_t info_address;   /* 信息对象地址 (=0) */
    qoi_t qualifier;           /* 初始化命令限定词 */
} C_CI_NA_1_t;

/**
 * @brief 复位进程命令结构 (C_RP_NA_1)
 */
typedef struct {
    info_addr_t info_address;   /* 信息对象地址 (=0) */
    qrp_t qualifier;           /* 复位进程命令限定词 */
} C_RP_NA_1_t;

/**
 * @brief 初始化结束结构 (M_EI_NA_1)
 */
typedef struct {
    info_addr_t info_address;   /* 信息对象地址 */
    coi_t cause;               /* 初始化原因 */
} M_EI_NA_1_t;

/**
 * @brief 系统命令类型枚举
 */
typedef enum {
    SYSTEM_CMD_TOTAL_INTERROGATION = 100,    /* 总召唤命令 */
    SYSTEM_CMD_ENERGY_INTERROGATION = 101,   /* 电能量召唤命令 */
    SYSTEM_CMD_CLOCK_SYNC = 103,             /* 时钟同步命令 */
    SYSTEM_CMD_TEST = 104,                   /* 测试命令 */
    SYSTEM_CMD_RESET_PROCESS = 105,          /* 复位进程命令 */
    SYSTEM_CMD_INITIALIZATION = 106,         /* 初始化命令 */
    SYSTEM_CMD_SWITCH_SETTING_AREA = 200,    /* 切换定值区 */
    SYSTEM_CMD_READ_SETTING_AREA = 201,      /* 读定值区号 */
    SYSTEM_CMD_READ_PARAMETER = 202,         /* 读参数和定值 */
    SYSTEM_CMD_WRITE_PARAMETER = 203,        /* 写参数和定值 */
    SYSTEM_CMD_FILE_TRANSFER = 210,         /* 文件传输 */
    SYSTEM_CMD_SOFTWARE_UPGRADE = 211       /* 软件升级 */
} system_command_type_t;

/**
 * @brief 召唤限定词枚举
 */
typedef enum {
    QOI_TOTAL_INTERROGATION = 20,           /* 总召唤 */
    QOI_GROUP1_INTERROGATION = 21,          /* 第1组召唤 */
    QOI_GROUP2_INTERROGATION = 22,          /* 第2组召唤 */
    QOI_GROUP3_INTERROGATION = 23,          /* 第3组召唤 */
    QOI_GROUP4_INTERROGATION = 24,          /* 第4组召唤 */
    QOI_GROUP5_INTERROGATION = 25,          /* 第5组召唤 */
    QOI_GROUP6_INTERROGATION = 26,          /* 第6组召唤 */
    QOI_GROUP7_INTERROGATION = 27,          /* 第7组召唤 */
    QOI_GROUP8_INTERROGATION = 28,          /* 第8组召唤 */
    QOI_GROUP9_INTERROGATION = 29,          /* 第9组召唤 */
    QOI_GROUP10_INTERROGATION = 30,         /* 第10组召唤 */
    QOI_GROUP11_INTERROGATION = 31,         /* 第11组召唤 */
    QOI_GROUP12_INTERROGATION = 32,         /* 第12组召唤 */
    QOI_GROUP13_INTERROGATION = 33,         /* 第13组召唤 */
    QOI_GROUP14_INTERROGATION = 34,         /* 第14组召唤 */
    QOI_GROUP15_INTERROGATION = 35,         /* 第15组召唤 */
    QOI_GROUP16_INTERROGATION = 36          /* 第16组召唤 */
} qoi_type_t;

/**
 * @brief 初始化原因枚举
 */
typedef enum {
    COI_LOCAL_POWER_ON = 0,                 /* 当地电源合上 */
    COI_LOCAL_MANUAL_RESET = 1,             /* 当地手动复位 */
    COI_REMOTE_RESET = 2                    /* 远方复位 */
} coi_type_t;

/**
 * @brief 复位进程命令限定词枚举
 */
typedef enum {
    QRP_PROCESS_RESET = 1                   /* 进程的总复位 */
} qrp_type_t;

/**
 * @brief 系统命令数据
 */
typedef struct {
    system_command_type_t command_type;     /* 命令类型 */
    info_addr_t info_address;               /* 信息对象地址 */
    union {
        qoi_interrogation_t qoi;                          /* 召唤限定词 */
        cp56time2a_t timestamp;             /* 时间戳 */
        qrp_t qrp;                          /* 复位进程命令限定词 */
        coi_t coi;                          /* 初始化原因 */
    } qualifier;                            /* 限定词联合体 */
    cp56time2a_t command_time;              /* 命令时间 */
    u8 execute_result;                       /* 执行结果：0-成功，1-失败 */
} system_command_data_t;

/**
 * @brief 系统命令数据组
 */
typedef struct {
    system_command_data_t* commands;        /* 系统命令数组 */
    u32 count;                              /* 命令个数 */
    u32 max_count;                          /* 最大命令个数 */
} system_command_data_group_t;

/* ==================== 系统命令数据转换函数 ==================== */

/**
 * @brief 总召唤命令转换为字节数组
 * @details 将总召唤命令结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化。
 * 
 * @param command 总召唤命令结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_VALUE: 数据值无效
 * 
 * @note 按照104协议规范进行数据序列化
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_general_interrogation_command
 * @see validate_general_interrogation_command
 * @see buffer_write_u32
 * @see buffer_write_u8
 */
protocol_error_t general_interrogation_command_to_bytes(const C_IC_NA_1_t* command,
                                                      u8* buffer, u32 buffer_size, u32* actual_length);

/**
 * @brief 字节数组转换为总召唤命令
 * @details 将104协议规定的字节数组格式转换为总召唤命令结构。
 *          按照协议规范进行数据反序列化。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param command 总召唤命令结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_VALUE: 数据值无效
 * 
 * @note 按照104协议规范进行数据反序列化
 * @warning 数据长度必须足够容纳总召唤命令
 * 
 * @see general_interrogation_command_to_bytes
 * @see validate_general_interrogation_command
 * @see buffer_read_u32
 * @see buffer_read_u8
 */
protocol_error_t bytes_to_general_interrogation_command(const u8* data, u32 length,
                                                      C_IC_NA_1_t* command);

/**
 * @brief 验证总召唤命令
 * @details 验证总召唤命令结构的完整性和有效性。
 *          检查地址和召唤限定词的有效性。
 * 
 * @param command 总召唤命令结构，不能为NULL
 * @return 验证结果
 *         - 1: 总召唤命令有效
 *         - 0: 总召唤命令无效
 * 
 * @note 验证地址和召唤限定词的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_qoi_valid
 * @see C_IC_NA_1_t
 */
int validate_general_interrogation_command(const C_IC_NA_1_t* command);

/**
 * @brief 初始化命令转换为字节数组
 * @details 将初始化命令结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化。
 * 
 * @param command 初始化命令结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_VALUE: 数据值无效
 * 
 * @note 按照104协议规范进行数据序列化
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_initialization_command
 * @see validate_initialization_command
 * @see buffer_write_u32
 * @see buffer_write_u8
 */
protocol_error_t initialization_command_to_bytes(const C_CI_NA_1_t* command,
                                               u8* buffer, u32 buffer_size, u32* actual_length);

/**
 * @brief 字节数组转换为初始化命令
 * @details 将104协议规定的字节数组格式转换为初始化命令结构。
 *          按照协议规范进行数据反序列化。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param command 初始化命令结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_VALUE: 数据值无效
 * 
 * @note 按照104协议规范进行数据反序列化
 * @warning 数据长度必须足够容纳初始化命令
 * 
 * @see initialization_command_to_bytes
 * @see validate_initialization_command
 * @see buffer_read_u32
 * @see buffer_read_u8
 */
protocol_error_t bytes_to_initialization_command(const u8* data, u32 length,
                                                C_CI_NA_1_t* command);

/**
 * @brief 验证初始化命令
 * @details 验证初始化命令结构的完整性和有效性。
 *          检查地址和初始化原因的有效性。
 * 
 * @param command 初始化命令结构，不能为NULL
 * @return 验证结果
 *         - 1: 初始化命令有效
 *         - 0: 初始化命令无效
 * 
 * @note 验证地址和初始化原因的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_qoi_valid
 * @see C_CI_NA_1_t
 */
int validate_initialization_command(const C_CI_NA_1_t* command);

/**
 * @brief 复位进程命令转换为字节数组
 * @details 将复位进程命令结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化。
 * 
 * @param command 复位进程命令结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_VALUE: 数据值无效
 * 
 * @note 按照104协议规范进行数据序列化
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_reset_process_command
 * @see validate_reset_process_command
 * @see buffer_write_u32
 * @see buffer_write_u8
 */
protocol_error_t reset_process_command_to_bytes(const C_RP_NA_1_t* command,
                                               u8* buffer, u32 buffer_size, u32* actual_length);

/**
 * @brief 字节数组转换为复位进程命令
 * @details 将104协议规定的字节数组格式转换为复位进程命令结构。
 *          按照协议规范进行数据反序列化。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param command 复位进程命令结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_VALUE: 数据值无效
 * 
 * @note 按照104协议规范进行数据反序列化
 * @warning 数据长度必须足够容纳复位进程命令
 * 
 * @see reset_process_command_to_bytes
 * @see validate_reset_process_command
 * @see buffer_read_u32
 * @see buffer_read_u8
 */
protocol_error_t bytes_to_reset_process_command(const u8* data, u32 length,
                                              C_RP_NA_1_t* command);

/**
 * @brief 验证复位进程命令
 * @details 验证复位进程命令结构的完整性和有效性。
 *          检查地址和复位进程命令限定词的有效性。
 * 
 * @param command 复位进程命令结构，不能为NULL
 * @return 验证结果
 *         - 1: 复位进程命令有效
 *         - 0: 复位进程命令无效
 * 
 * @note 验证地址和复位进程命令限定词的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_reset_valid
 * @see C_RP_NA_1_t
 */
int validate_reset_process_command(const C_RP_NA_1_t* command);

/**
 * @brief 时钟同步命令转换为字节数组
 * @details 将时钟同步命令结构转换为104协议规定的字节数组格式。
 *          按照协议规范进行数据序列化。
 * 
 * @param command 时钟同步命令结构，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_length 实际写入长度输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP: 时间戳无效
 * 
 * @note 按照104协议规范进行数据序列化
 * @warning 缓冲区大小必须足够容纳转换后的数据
 * 
 * @see bytes_to_clock_sync_command
 * @see validate_clock_sync_command
 * @see buffer_write_u32
 * @see cp56time2a_to_bytes
 */
protocol_error_t clock_sync_command_to_bytes(const C_CS_NA_1_t* command,
                                            u8* buffer, u32 buffer_size, u32* actual_length);

/**
 * @brief 字节数组转换为时钟同步命令
 * @details 将104协议规定的字节数组格式转换为时钟同步命令结构。
 *          按照协议规范进行数据反序列化。
 * 
 * @param data 字节数组，不能为NULL
 * @param length 数据长度
 * @param command 时钟同步命令结构输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 转换成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 数据长度不足
 *         - PROTOCOL_ERROR_ASDU_INVALID_ADDRESS: 地址无效
 *         - PROTOCOL_ERROR_DATA_INVALID_TIMESTAMP: 时间戳无效
 * 
 * @note 按照104协议规范进行数据反序列化
 * @warning 数据长度必须足够容纳时钟同步命令
 * 
 * @see clock_sync_command_to_bytes
 * @see validate_clock_sync_command
 * @see buffer_read_u32
 * @see bytes_to_cp56time2a
 */
protocol_error_t bytes_to_clock_sync_command(const u8* data, u32 length,
                                           C_CS_NA_1_t* command);

/**
 * @brief 验证时钟同步命令
 * @details 验证时钟同步命令结构的完整性和有效性。
 *          检查地址和时间戳的有效性。
 * 
 * @param command 时钟同步命令结构，不能为NULL
 * @return 验证结果
 *         - 1: 时钟同步命令有效
 *         - 0: 时钟同步命令无效
 * 
 * @note 验证地址和时间戳的有效性
 * @warning 输入指针不能为NULL
 * 
 * @see is_info_address_valid
 * @see is_cp56time2a_valid
 * @see C_CS_NA_1_t
 */
int validate_clock_sync_command(const C_CS_NA_1_t* command);

/* ==================== 辅助函数 ==================== */

/**
 * @brief 获取总召唤命令大小
 * @details 获取总召唤命令结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 总召唤命令大小（字节）
 * 
 * @note 总召唤命令大小：4字节（地址3字节 + QOI1字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_initialization_command_size
 * @see get_reset_process_command_size
 * @see C_IC_NA_1_t
 */
u32 get_general_interrogation_command_size(void);

/**
 * @brief 获取初始化命令大小
 * @details 获取初始化命令结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 初始化命令大小（字节）
 * 
 * @note 初始化命令大小：4字节（地址3字节 + COI1字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_general_interrogation_command_size
 * @see get_reset_process_command_size
 * @see C_CI_NA_1_t
 */
u32 get_initialization_command_size(void);

/**
 * @brief 获取复位进程命令大小
 * @details 获取复位进程命令结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 复位进程命令大小（字节）
 * 
 * @note 复位进程命令大小：4字节（地址3字节 + QRP1字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_general_interrogation_command_size
 * @see get_initialization_command_size
 * @see C_RP_NA_1_t
 */
u32 get_reset_process_command_size(void);

/**
 * @brief 获取时钟同步命令大小
 * @details 获取时钟同步命令结构在字节数组中的大小。
 *          用于缓冲区大小计算。
 * 
 * @return 时钟同步命令大小（字节）
 * 
 * @note 时钟同步命令大小：10字节（地址3字节 + 时间戳7字节）
 * @warning 此函数是线程安全的
 * 
 * @see get_general_interrogation_command_size
 * @see get_initialization_command_size
 * @see C_CS_NA_1_t
 */
u32 get_clock_sync_command_size(void);

/* ==================== 验证辅助函数 ==================== */

/**
 * @brief 验证召唤限定词
 * @details 验证QOI（召唤限定词）是否在104协议规定的有效范围内。
 *          检查保留位是否都为0。
 * 
 * @param qoi 召唤限定词
 * @return 验证结果
 *         - 1: QOI有效
 *         - 0: QOI无效
 * 
 * @note QOI只有7位有效，其他位必须为0
 * @warning 保留位必须为0
 * 
 * @see is_qoi_valid
 * @see is_reset_valid
 * @see qoi_t
 */
int is_qoi_valid_system(const qoi_interrogation_t* qoi);

/**
 * @brief 验证初始化原因
 * @details 验证COI（初始化原因）是否在104协议规定的有效范围内。
 *          检查保留位是否都为0。
 * 
 * @param coi 初始化原因
 * @return 验证结果
 *         - 1: COI有效
 *         - 0: COI无效
 * 
 * @note COI只有7位有效，其他位必须为0
 * @warning 保留位必须为0
 * 
 * @see is_qoi_valid
 * @see is_reset_valid
 * @see coi_t
 */
int is_coi_valid(const coi_t* coi);

/**
 * @brief 验证复位进程命令限定词
 * @details 验证QRP（复位进程命令限定词）是否在104协议规定的有效范围内。
 *          检查保留位是否都为0。
 * 
 * @param qrp 复位进程命令限定词
 * @return 验证结果
 *         - 1: QRP有效
 *         - 0: QRP无效
 * 
 * @note QRP只有7位有效，其他位必须为0
 * @warning 保留位必须为0
 * 
 * @see is_qoi_valid
 * @see is_qoi_valid
 * @see qrp_t
 */
int is_reset_valid(const qrp_t* qrp);

/* ==================== 系统命令类型处理函数 ==================== */

/**
 * @brief 获取系统命令类型名称
 * @details 根据系统命令类型枚举值获取对应的中文名称。
 *          用于调试和日志输出。
 * 
 * @param type 系统命令类型枚举值
 * @return 系统命令类型名称字符串
 * 
 * @note 返回的字符串是静态的，不需要释放
 * @warning 无效类型返回"未知类型"
 * 
 * @see system_command_type_t
 * @see get_system_command_type_description
 */
const char* get_system_command_type_name(system_command_type_t type);

/**
 * @brief 获取系统命令类型描述
 * @details 根据系统命令类型枚举值获取对应的详细描述。
 *          用于调试和日志输出。
 * 
 * @param type 系统命令类型枚举值
 * @return 系统命令类型描述字符串
 * 
 * @note 返回的字符串是静态的，不需要释放
 * @warning 无效类型返回"未知类型"
 * 
 * @see system_command_type_t
 * @see get_system_command_type_name
 */
const char* get_system_command_type_description(system_command_type_t type);

#ifdef __cplusplus
}
#endif

#endif /* SYSTEM_DATA_H */
